#pragma once
#include "Model.h"
#include "Types.h"
#include <vector>
#include "Simulator.h"

extern "C" void ExecuteIntegrate(void* pos, void* prevPos, unsigned int particleCount, float dt);
//extern "C" 
void ExecuteDistanceConstraintGPU(float4* pos, float4 *springs, unsigned int springCount, int iterations, float dt);


class GPUSimulator : Simulator
{
public:
	GPUSimulator(ID3D10Device *device);
	~GPUSimulator(void);

	HRESULT SetModel(Model<Vector4> *model);
	void Step(float dt);

	ID3D10Buffer *GetVertexBuffer();
private:
	// El dispositivo (GPU) donde vamos a crear los buffers.
	ID3D10Device* device;

	// Buffers en memoria de video.
	// Index buffer para dibujar los triangulos.
	ID3D10Buffer *pIndices;

	// Particulas
	ID3D10Buffer *dPositions;				// Posicion actual de Particulas
	ID3D10Buffer *dPrevPositions;			// Posicion anterior de Particulas

	// Resortes
	ID3D10Buffer *dArraySizes;				// Contiene enteros que representan el tamano de cada set de resortes.
	void *dSpringArrays;					// Contiene apuntadores a cada set de resortes cuyo tamano esta especificado por dArraySizes.
	std::vector<deviceBuffer> dSprings;		// Almacena temporalmente los elementos de dArraySizes y dSpringArrays.


	// Buffers en memoria de sistema
	float4 *hPositions;
	float4 *hPrePositions;
	int *hArraySizes;
	IntFloat4 *hSprings;

	int springCount;
	// El tamanio maximo de los sets de springs.
	int largestArraySize;
	Model<Vector4> *model;

	// Estos son los apuntadores que el kernel de CUDA puede usar
	// son buffers originalmente creados con D3D por lo que hay
	// que mapear esos apuntadores y obtenemos estos que si son
	// usables por un kernel. El void** de los springs es creado
	// directamente con CUDA por lo que no hace falta mapearlo.
	void* dPosMappedPtr;
	void* dPrevPosMappedPtr;
	void* dArraySizesMappedPtr;

	// Este metodo registra y mapea todos los buffers de D3D
	// para que los podamos utilizar desde un kernel de CUDA.
	void InitCuda();

	// Metodo para desmapear los buffers registrados con CUDA.
	void Dispose();
};
